# coding: utf-8
from util import findItem

class Heranca:
    def __init__(self,classes,heranca):
        child_c =  findItem(heranca,"UML:Generalization.child")[0]
        child_class =  findItem(child_c,"UML:Class")[0]
        parent_c =  findItem(heranca,"UML:Generalization.parent")[0]
        parent_class =  findItem(parent_c,"UML:Class")[0]

        filho = classes.get_nome(child_class.attributes.get('xmi.idref').value)
        pai   = classes.get_nome(parent_class.attributes.get('xmi.idref').value)
        
        cl = classes.get_classe(child_class.attributes.get('xmi.idref').value)
        cl.herda_de =  pai

class Associacao:
    def __init__(self,classes,assoc):
    
        connection =  findItem(assoc,"UML:Association.connection")[0]
        ass1,ass2 =  findItem(connection,"UML:AssociationEnd")
        ass1_tp = ass1.attributes.get('aggregation').value
        ass2_tp = ass2.attributes.get('aggregation').value
        ass1_part = findItem(ass1,"UML:AssociationEnd.participant")[0]
        ass1_class =  findItem(ass1_part,"UML:Class")[0]

        ass2_part = findItem(ass2,"UML:AssociationEnd.participant")[0]
        ass2_class =  findItem(ass2_part,"UML:Class")[0]

        ass1_mult = findItem(ass2,"UML:AssociationEnd.multiplicity")[0]
        ass1_mult = findItem(ass1_mult,"UML:Multiplicity")[0]
        ass1_mult = findItem(ass1_mult,"UML:Multiplicity.range")[0]
        ass1_mult = findItem(ass1_mult,"UML:MultiplicityRange")[0]

        ass2_mult = findItem(ass1,"UML:AssociationEnd.multiplicity")[0]
        ass2_mult = findItem(ass2_mult,"UML:Multiplicity")[0]
        ass2_mult = findItem(ass2_mult,"UML:Multiplicity.range")[0]
        ass2_mult = findItem(ass2_mult,"UML:MultiplicityRange")[0]

        #print '%s <> %s' %( ass1_mult.attributes.get('upper').value,ass2_mult.attributes.get('upper').value  )
        if  ass1_mult.attributes.get('lower').value != '1' or ass2_mult.attributes.get('lower').value != '1':
            raise Exception('a cardinalidade minima deve ser 1')

        #print ass1_mult.attributes.get('upper').value
        if ass1_tp == ass2_tp:
            raise Exception('as associações não devem ser iguais')
        
        ass2_tp
        if ass1_tp == 'none':
            classe =classes.self.get_classe(ass1_class.attributes.get('xmi.idref').value)
            self.classe = classes.get_nome(ass2_class.attributes.get('xmi.idref').value)
            self.agregacao = ass2_tp
            self.cardinalidade = [ass2_mult.attributes.get('upper').value,ass1_mult.attributes.get('upper').value]
            self.extras = []
            self.verifica_extras()
        else:
            classe =classes.get_classe(ass2_class.attributes.get('xmi.idref').value)
            self.classe = classes.get_nome(ass1_class.attributes.get('xmi.idref').value)
            self.agregacao = ass1_tp
            self.cardinalidade = [ass1_mult.attributes.get('upper').value,ass2_mult.attributes.get('upper').value]
            self.extras = []
            self.verifica_extras()
        if self.cardinalidade[0] != '1':
            self.cardinalidade[0] = '*'
        if self.cardinalidade[1] != '1':
            self.cardinalidade[1] = '*'

        classe.addAssociacao(self)

    def verifica_extras(self):
        if self.cardinalidade[0] == '1' and self.cardinalidade[1] == '1':
            self.extras.append(dict(nome='unique'
                                   ,valor=True))



class Atributo:
    def __init__(self,att,lst_tipos,lst_tags):
        container_tipo = findItem(att,'UML:StructuralFeature.type')[0]
        container_tipo2 = findItem(container_tipo,'UML:DataType')[0]
        self.nome = att.attributes.get('name').value
        self.valor= lst_tipos.get_nome(container_tipo2.attributes.get('xmi.idref').value)
        self.extras = []
        self.verifica_extras(att,lst_tags)

    def verifica_extras(self,att,lst_tags):
        #associa os itens dos valores marcados
        container_att = findItem(att,'UML:ModelElement.taggedValue')
        if container_att: #verifica se há valores marcados
            atts = findItem(container_att[0],'UML:TaggedValue')
            for at in atts:
                atts_name = findItem(at,'UML:TaggedValue.type')[0]
                atts_def = findItem(atts_name,'UML:TagDefinition')[0]
                atts_value = findItem(at,'UML:TaggedValue.dataValue')[0].childNodes[0] 
                self.extras.append(dict(nome=lst_tags.get_nome(atts_def.attributes.get('xmi.idref').value)
                                       ,valor=atts_value.nodeValue))

class ListaClasses:
    def __init__(self,xmi_classes,lst_tipos,lst_tags,xmi_associacoes,xmi_herancas):
        self.lista = []
        for classe in xmi_classes:
            cl = Klasse(classe.attributes.get('name').value
                       ,classe.attributes.get('xmi.id').value)
            container = findItem(classe,'UML:Classifier.feature')[0]
            xmi_atributos = findItem(container,'UML:Attribute')
            for att in xmi_atributos:
                cl.addAtributo(att,lst_tipos,lst_tags)
            self.lista.append(cl)
            
        for assoc in xmi_associacoes:
            Associacao(self,assoc)
        for heran in xmi_herancas:
            Heranca(self,heran)
            

    def get_classe(self,xmi_id):
        for c in self.lista:
            if c.xmi_id == xmi_id:
                return c


    def get_nome(self,xmi_id):
        for t in self.lista:
            if t.xmi_id == xmi_id:
                return t.nome


class Klasse:

    def __init__(self,nome,xmi_id):
        self.nome = nome
        self.xmi_id = xmi_id
        self.atributos = []
        self.associacoes = []
        self.herda_de = None

    def addAssociacao(self,assoc):
        self.associacoes.append(assoc)

    def addAtributo(self,att,lst_tipos,lst_tags):
        self.atributos.append(Atributo(att,lst_tipos,lst_tags))

    def get_id(self):
        return self.xmi_id


    def listar(self):
        print "%s - %s" % (self.nome,self.xmi_id)
        for a in self.atributos:
            print ' - %s (%s)' %(a.nome,a.valor)
        for a in self.associacoes:
            print ' - %s %s %s' %(a.classe,a.agregacao,a.cardinalidade)


class TipoTags:
    def __init__(self,xmi_tags):
        self.tags = []
        for tag in xmi_tags:
            tp = self.exportaValores(tag)
            self.inserir(tp[0],tp[1])
    def exportaValores(self,xmi):
        return (xmi.attributes.get('name').value
               ,xmi.attributes.get('xmi.id').value)

    def inserir(self,nome,xmi_id):
        tp = dict(nome=nome
                 ,xmi_id=xmi_id)
        self.tags.append(tp)
  

    def listar(self):
        return self.tags

    def get_xmi_id(self,nome):
        for t in self.tags:
            if t['nome'] == nome:
                return t['xmi_id']

    def get_nome(self,xmi_id):
        for t in self.tags:
            if t['xmi_id'] == xmi_id:
                return t['nome']

   
class TipoDados:
    def __init__(self,xmi_tipos):
        self.tipos = []
        for tipo in xmi_tipos:
            tp = self.exportaValoresTipo(tipo)
            self.inserir(tp[0],tp[1])

    def exportaValoresTipo(self,xmlTipo):
        """
        retorna o nome e a identificação do XMI
        """
        return xmlTipo.attributes.get('name').value, xmlTipo.attributes.get('xmi.id').value

    def inserir(self,nome,xmi_id):
        tp = dict(nome=nome
                 ,xmi_id=xmi_id)
        self.tipos.append(tp)

    def listar(self):
        return self.tipos

    def get_xmi_id(self,nome):
        for t in self.tipos:
            if t['nome'] == nome:
                return t['xmi_id']

    def get_nome(self,xmi_id):
        for t in self.tipos:
            if t['xmi_id'] == xmi_id:
                return t['nome']
